﻿using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using NHibernate.Cfg;
using System.Diagnostics.Contracts;

namespace DataStore
{
    /// <summary>
    /// NHibernate configuration handler
    /// </summary>
    public class NHibConfigHandler
    {
        /// <summary>
        /// Name of serialized NHibernate configuration file
        /// </summary>
        private const string SerializedConfig = "nhibconf.ser";
        /// <summary>
        /// Path to application configuration folder
        /// </summary>
        public string ConfigDataPath { get; internal set; }
        /// <summary>
        /// Path to serialized configuration file
        /// </summary>
        public string ConfigDataFile { get; internal set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="NHibConfigHandler"/> class.
        /// </summary>
        public NHibConfigHandler()
        {
            ConfigDataPath = string.Format(CultureInfo.InvariantCulture,
                    @"{0}\{1}",
                    System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData),
                    Properties.Settings.Default.ApplicationDataFolder);
            ConfigDataFile = Path.Combine(ConfigDataPath, SerializedConfig);
        }

        /// <summary>
        /// Saves the NHibernate configuration to file.
        /// </summary>
        /// <param name="config">The config.</param>
        public void SaveConfigurationToFile(Configuration config)
        {
            Contract.Requires(config != null);
            Contract.Requires(!string.IsNullOrEmpty(ConfigDataPath));


            if (!Directory.Exists(ConfigDataPath))
            {
                Directory.CreateDirectory(ConfigDataPath);
            }

            using (var file = System.IO.File.Open(ConfigDataFile, FileMode.Create))
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(file, config);

            }
        }

        /// <summary>
        /// Loads the NHibernate configuration from file.
        /// </summary>
        /// <returns></returns>
        public Configuration LoadConfigurationFromFile()
        {

            if (IsConfigurationFileValid == false)
                return null;

            Configuration config = null;
            try
            {
                using (var file = System.IO.File.Open(ConfigDataFile, FileMode.Open))
                {
                    var bf = new BinaryFormatter();
                    config = bf.Deserialize(file) as Configuration;
                    return config;
                }
            }
            catch (Exception ex)
            {
                // COM+ Exception occures, not handled by .NET FW; ex==null
                if (ex != null)
                {
                    return null;
                }
                else
                {
                    return config;
                }
            }

        }


        /// <summary>
        /// Determines whether [configuration file is valid].
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is configuration file valid; otherwise, <c>false</c>.
        /// </value>
        /// <returns>
        /// 	<c>true</c> if [configuration file is valid]; otherwise, <c>false</c>.
        /// </returns>
        private bool IsConfigurationFileValid
        {

            get
            {
                Contract.Requires(!string.IsNullOrEmpty(ConfigDataFile ));

                var ass = Assembly.GetCallingAssembly();
                if (ass.Location == null)
                    return false;
                var configInfo = new FileInfo(ConfigDataFile);
                var assInfo = new FileInfo(ass.Location);
                var configFileInfo = new FileInfo(SerializedConfig);
                if (configInfo.LastWriteTime < assInfo.LastWriteTime)
                    return false;
                if (configInfo.LastWriteTime < configFileInfo.LastWriteTime)
                    return false;
                return true;
            }

        }

    }
}
